# -*- coding: utf-8 -*-
"""
xfree.plugins.utils
~~~~~~~~~~~~~~~~~~~~~

这个模块提供了插件的注册以及基于数据库的基本键值对存储功能。

"""

from flask import current_app, flash, redirect, url_for
from flask_babelplus import gettext as _
from markupsafe import Markup

from xfree.extensions import db
from xfree.plugins.models import PluginRegistry
from xfree.utils.datastructures import TemplateEventResult


def template_hook(name, silent=True, is_markup=True, **kwargs):
    """调用给定名称的模板钩子函数。

    :param name: 钩子的名称。
    :param silent: 如果设置为 False，当钩子不存在时会抛出异常；默认值为 True，表示钩子不存在时不抛出异常，而是返回空字符串。
    :param is_markup: 决定钩子是否应该返回一个 Markup 对象；默认值为 True，如果设置为 False，则返回一个 TemplateEventResult 对象。
    :param kwargs: 传递给钩子函数的额外关键字参数。
    """
    try:
        # 尝试获取钩子函数并调用它，将结果包装成 TemplateEventResult 对象。
        hook = getattr(current_app.pluggy.hook, name)
        result = TemplateEventResult(hook(**kwargs))
    except AttributeError:  # 当钩子不存在时会抛出 AttributeError 异常。
        if silent:
            return ""
        raise

    if is_markup:
        # 如果 is_markup 为 True，将结果转换为 Markup 对象并返回。
        return Markup(result)

    # 如果 is_markup 为 False，直接返回 TemplateEventResult 对象。
    return result


def validate_plugin(name):
    """尝试查找给定名称的插件，如果插件不存在，则显示错误消息并重定向到插件管理页面。

    :param name: 要查找的插件名称。
    :return: 如果插件存在，返回插件模块；如果插件不存在，重定向到插件管理页面并返回 None。
    """
    # 获取指定名称的插件模块。
    plugin_module = current_app.pluggy.get_plugin(name)
    if plugin_module is None:
        # 如果插件不存在，显示错误消息并重定向到插件管理页面。
        flash(_("插件 %(plugin)s 未找到。", plugin=name), "error")
        return redirect(url_for("admin.plugins"))
    return plugin_module


def remove_zombie_plugins_from_db():
    """从数据库中删除“僵尸”插件，即存在于数据库中但在环境中不再安装的插件。

    :return: 返回已删除的插件名称列表。
    """
    # 获取插件管理器中已禁用的插件名称列表。
    d_fs_plugins = [p[0] for p in current_app.pluggy.list_disabled_plugins()]
    # 获取数据库中已禁用的插件名称列表。
    d_db_plugins = [p.name for p in PluginRegistry.query.filter_by(enabled=False).all()]

    # 获取数据库中所有插件的名称列表。
    plugin_names = [p.name for p in PluginRegistry.query.all()]

    remove_me = []
    for p in plugin_names:
        # 确定要删除的“僵尸”插件，即存在于数据库中已禁用但不在插件管理器已禁用列表中的插件。
        if p in d_db_plugins and p not in d_fs_plugins:
            remove_me.append(p)

    if len(remove_me) > 0:
        # 如果有要删除的插件，使用数据库查询语句删除这些插件，并提交事务。
        PluginRegistry.query.filter(PluginRegistry.name.in_(remove_me)).delete(
            synchronize_session="fetch"
        )
        db.session.commit()
    return remove_me